home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / sortdir2.arc / SORTDIR2.ASM < prev    next >
Assembly Source File  |  1991-09-15  |  51KB  |  1,180 lines

  1. PAGE 84,132
  2. ;-----------------------------------------------------------------------------|
  3. ;  ---- ScanSoft(tm) SORTDIR (C)1991 Cornel Huth -- All Rights Reserved ----  |
  4. ;-----------------------------------------------------------------------------|
  5. ;  program:     SORTDIR.ASM                                                   |
  6. ;  version:     1.02                          COPYRIGHT 1991 Cornel Huth      |
  7. ;       by:     Cornel Huth              6402 Ingram Rd/San Antonio, TX/78238 |
  8. ;     date:     09-Sep-91                                                     |
  9. ; function:     sort current directory                                        |
  10. ;   caller:     COMMAND                                                       |
  11. ;      use:                                                                   |
  12. ;                                                                             |
  13. ;   C>SD [options] * sort current directory by filename [options]             |
  14. ;   options:                                                                  |
  15. ;     SD /e    * by ext.filename (default)                                    |
  16. ;     SD /n    * by filename.ext                                              |
  17. ;     SD /h    * help with anything other CLP                                 |
  18. ;-----------------------------------------------------------------------------|
  19. ;NOTES:                                                                       |
  20. ;Code requires DOS 3.2+ for IOCTL functions                                   |
  21. ;Requires MASM 5.1 to assemble                                                |
  22. ;Should work on any DOS machine since everything is DOS done                  |
  23. ;User documentation found, where else, in the User Documentation              |
  24. ;LIMITATIONS: (some could be considered benifits)                             |
  25. ;Operates on current drive/current directory only                             |
  26. ;Will not sort entries prior to any hidden, system, or subdirectory entries   |
  27. ;Root directory must lie in the first 64K sectors of the DOS drive(no problem)|
  28. ;FAT must be less than 64K (no problem)                                       |
  29. ;Maximum of 1792 directory entries per subdirectory (seems like enough)       |
  30. ;Sort source not included (how does that grab you?)                           |
  31. ;-----------------------------------------------------------------------------|
  32. ;Being a programmer I'm always deleting working files. I like to keep my subs |
  33. ;packed and files grouped by extension. 32MB+ parts made Norton DS unusable so|
  34. ;PCTools 4.22 had been used to sort subdirs on large DOS 3.31 parts. HOWEVER, |
  35. ;in writing this code (using PCT422 for direct disk access) I noticed PCT422  |
  36. ;becomes real flakey (try accessing, say, cluster# 18,000, or even 10,000)--  |
  37. ;--a real good reason to have a dir sort program written for large partitions.|
  38. ;One reason for this is that previous DOS versions had a total sector count   |
  39. ;indicating the number of sectors on a drive. If it was 4086 or less then the |
  40. ;FAT used 12-bit entries, 4087 or more, 16-bit entries. In DOS versions that  |
  41. ;allow large partitions, the total sector count is not large enough to express|
  42. ;sector counts above 64K. What these do then is set the regular total sector  |
  43. ;count to 0 and in another location set a 32-bit entry to the total sectors.  |
  44. ;What is probably happening is that programs unaware of the new DOS tactic is |
  45. ;checking for a total sector count less than 4087 (which it is on large parts)|
  46. ;and if so, assumes a 12-bit FAT!  Some programs see the 0 for what it is,    |
  47. ;somewhat, and indicate that the FAT scheme is unknown.                       |
  48. ;-----------------------------------------------------------------------------|
  49. ;   NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: NOTICE:   |
  50. ;-----------------------------------------------------------------------------|
  51. ; >>>>>>>>>>>>>>>>> THIS SOURCE CODE IS *NOT* PUBLIC DOMAIN <<<<<<<<<<<<<<<<< |
  52. ;-----------------------------------------------------------------------------|
  53. ;I allow you to modify this source ONLY for your personal, non-commercial use |
  54. ;You may NOT distribute this source if altered in any way                     |
  55. ;You may NOT distribute any directory sorting program derived from this source|
  56. ;If you can't abide by these terms then don't use any of this code.           |
  57. ;-----------------------------------------------------------------------------|
  58. ;C>masm sd.asm;
  59. ;C>link /cp:1 sd,sd.exe; (MUST LINK WITH /cp:1)
  60. ;-----------------------------------------------------------------------------|
  61. ;1.00-chh 2-Sep-91 Initial release
  62. ;1.01-chh 6-Sep-91 A1* Change entries-to-sort parm (CX) of Quiksort to position-
  63. ;of-last-sort-item since we're not starting sort (necessarily) at item 1
  64. ;1.02-chh 9-Sep-91 B0* Change stack to 1024 bytes from 512
  65. ;B1* Move DOS 1 ret setup to start of program for correct PSP segment push
  66. ;B2* Increase max directory entries to 1792 and correct too many clusters check
  67. ;since previous code check based on 1 sector/cluster
  68. ;B3* Change default sort order to ext.filename
  69. ;B4* Floppies will have byte F6h in the root directory from the format--need to
  70. ;explicitly check for the entry being unused (byte0=0) and not assume that
  71. ;if it is unused that all the bytes will be that way. Thanks K.B.
  72. ;-----------------------------------------------------------------------------|
  73.  
  74. WPTR    EQU <WORD PTR>
  75. BPTR    EQU <BYTE PTR>
  76.  
  77. STDIN   EQU 0
  78. STDOUT  EQU 1
  79. STDERR  EQU 2
  80.  
  81. MAXDIR  EQU 1792 ;B2* max directory entries per subdir (1792=56K)
  82.                   ;(MAXDIR*32 should be evenly divisble by cluster size in bytes)
  83.                   ;for all cluster size from 512,1024,2048,4096,8192 the full
  84.                   ;1792 entries are available, 16K clusters can have 1536 avail
  85.  
  86. DeviceParms     STRUC           ;DEVICE PARMS STRUCTURE
  87.  dpSpecFunc     db 1 DUP (?)    ;special functions
  88.  dpDevType      db 1 DUP (?)    ;device type
  89.  dpDevAttr      dw 1 DUP (?)    ;device attribute
  90.  dpCylinders    dw 1 DUP (?)    ;number of cylinders
  91.  dpMediaType    db 1 DUP (?)    ;media type
  92.                                 ;BPB follows
  93.  dpBytesSector  dw 1 DUP (?)    ;bytes per sector
  94.  dpSectorsClust db 1 DUP (?)    ;sectors per cluster
  95.  dpResSectors   dw 1 DUP (?)    ;reserved sectors
  96.  dpFATs         db 1 DUP (?)    ;number of FATs
  97.  dpRootDirEnts  dw 1 DUP (?)    ;root directory entries
  98.  dpSectors      dw 1 DUP (?)    ;if 0 then > 32MB DOS drive, use dpHugeSectors
  99.  dpMedia        db 1 DUP (?)    ;media byte
  100.  dpFATsecs      dw 1 DUP (?)    ;sectors used by each FAT
  101.  dpSectorsTrack dw 1 DUP (?)    ;sectors per track
  102.  dpHeads        dw 1 DUP (?)    ;heads
  103.  dpHiddenSecs   dd 1 DUP (?)    ;hidden sectors
  104.  dpHugeSectors  dd 1 DUP (?)    ;number of sectors if dpSectors=0
  105. DeviceParms     ENDS
  106.  
  107. rwBlock         STRUC           ;READ/WRITE TRACK ON LOGICAL DRIVE STRUCTURE
  108.  rwSpecFunc     db 1 DUP (?)
  109.  rwHead         dw 1 DUP (?)
  110.  rwCylinder     dw 1 DUP (?)
  111.  rwFirstSector  dw 1 DUP (?)
  112.  rwSectors      dw 1 DUP (?)
  113.  rwBuffer       dd 1 DUP (?)
  114. rwBlock         ENDS
  115.  
  116. DirEntry        STRUC           ;DIRECTORY ENTRY STRUCTURE
  117.  deName         db 8 DUP (?)
  118.  deExtension    db 3 DUP (?)
  119.  deAttributes   db 1 DUP (?)
  120.  deReserved     db 10 DUP (?)
  121.  deTime         dw 1 DUP (?)
  122.  deDate         dw 1 DUP (?)
  123.  deStartCluster dw 1 DUP (?)
  124.  deFileSize     dd 1 DUP (?)
  125. DirEntry        ENDS
  126.  
  127.                 DOSSEG
  128.                 .MODEL SMALL
  129.                 .STACK 1024     ;B0* more stack for the expand sort buffer
  130.  
  131.                 .DATA?          ;simplified segment directives use DGROUP offset
  132.  
  133. MajorV          db 1 DUP (?)    ;DOS version
  134. MinorV          db 1 DUP (?)    ;-
  135. INT24error      dw 1 DUP (?)    ;DOS fatal error
  136. INT24seg        dw 1 DUP (?)    ;original INT24 vector
  137. INT24off        dw 1 DUP (?)    ;-DOS restores on program exit
  138. INT23seg        dw 1 DUP (?)    ;original INT23 vector
  139. INT23off        dw 1 DUP (?)    ;-DOS restores on program exit
  140. INT1Bseg        dw 1 DUP (?)    ;original INT1B vector
  141. INT1Boff        dw 1 DUP (?)    ;-must be restored before exiting (BIOS vector)
  142. INT00seg        dw 1 DUP (?)    ;original INT00 vector
  143. INT00off        dw 1 DUP (?)    ;-must be restored before exiting (BIOS vector)
  144. PSPseg          dw 1 DUP (?)    ;PSP segment at load time
  145. SegBuffFAT      dw 1 DUP (?)    ;segment of buffer for FAT
  146. SegBuffFAT2     dw 1 DUP (?)    ;segment of buffer for FAT2
  147. FATtype         db 1 DUP (?)    ;12 or 16 for FAT bit size
  148. CurrDrive       db 1 DUP (?)    ;current DOS drive (default)
  149. CurrDir         db 64 DUP (?)   ;current DOS directory
  150. StartCluster    dw 1 DUP (?)    ;starting cluster of subdirectory
  151. ClusterList     dw MAXDIR/16/1 DUP (?)  ;cluster link list (say, 112)
  152.                                 ;(1792 entries/16 ent/sec/clust (1 sec/cluster))
  153. ClusterListOF   dw 1 DUP (?)    ;end of link marker overflow
  154. FATsector       dw 1 DUP (?)    ;logical DOS sector of first FAT
  155. ROOTsector      dw 1 DUP (?)    ;logical DOS sector of root directory
  156. DATAsector      dw 1 DUP (?)    ;logical DOS sector of data start
  157. BytesCluster    dw 1 DUP (?)    ;bytes per cluster
  158. LOGSEC          dd 1 DUP (?)    ;logical DOS sector (32-bit)
  159. DOScylinder     dw 1 DUP (?)    ;format for IOCTL Read Track
  160. DOShead         dw 1 DUP (?)    ; "
  161. DOSsector       dw 1 DUP (?)    ; "
  162.  
  163. lo              dw 1 DUP (?)    ;Quiksort data
  164. hi              dw 1 DUP (?)
  165. reclen          dw 1 DUP (?)
  166. cstart          dw 1 DUP (?)
  167. cbytes          db 1 DUP (?)
  168.                 db 1 DUP (?)    ;even it up
  169. sptr            dw 1 DUP (?)
  170. Swap1           dw 1 DUP (?)    ;->start of record to swap
  171. Swap2           dw 1 DUP (?)    ;->start of record to swap
  172. TmpReg          dw 1 DUP (?)
  173.  
  174. rBlock          rwBlock <>      ;IOCTL read track info
  175. wBlock          rwBlock <>      ;IOCTL write track info
  176. BuffDeviceParms DeviceParms <>  ;device parameters
  177. EVEN
  178. BuffDirSort     DirEntry 1+MAXDIR+1 DUP (<>) ;directory entry slots (@#$!)
  179.                                              ;1 first for Quiksort work space
  180.                                              ;1 extra for count check
  181.                 .DATA
  182.  
  183. IDmsg           db 'SORTDIR 1.02 (C) 1991 Cornel Huth - All Rights Reserved',13,10
  184. IDmsgL          =$-IDmsg
  185.  
  186. CRLF            db 13,10
  187. CurrDrvMsgPre   db 'Sorting '
  188. CurrDrvMsg      db 'Z:\'
  189. CurrDrvMsgPreL  =$-CurrDrvMsgPre
  190.  
  191. MSortInfo       db 'Entries skipped/sorted '    ;sorted excludes deleted entries
  192. SortInfo        db 9 DUP (' ')                  ;max 4 +'/'+ 4
  193. MSortInfoL      =$-MSortInfo
  194.  
  195. EDoneNo         =0
  196. EDone           db 'ok'
  197. EDoneL          =$-EDone
  198. EDOSNo          =1
  199. MinDOS          EQU 0314h
  200. EDOS            db 'Requires DOS 3.20+'
  201. EDOSL           =$-EDOS
  202.                 db '$'                          ;for DOS 1 message
  203. EUnkSwitchNo    =2
  204. EUnkSwitch      db '* Invalid switch. Use: C>sd [/<en>]',13,10,13,10
  205.                 db 9,'On current drive/directory sort directory by:',13,10
  206.                 db 9,'/e ext.filename (default)',13,10    ;B3*
  207.                 db 9,'/n filename.ext',13,10
  208. EUnkSwitchL     =$-EUnkSwitch
  209. EInvalidDrvNo   =3
  210. EInvalidDrv     db 'Invalid drive'              ;remote drive
  211. EInvalidDrvL    =$-EInvalidDrv
  212. EAccessNo       =4
  213. EAccess         db 'Cannot access media'        ;r/w fault
  214. EAccessL        =$-EAccess
  215. EUnkDeviceNo    =5
  216. EUnkDevice      db 'Unknown DOS device'         ;e.g., 8-in floppy
  217. EUnkDeviceL     =$-EUnkDevice
  218. ERootFarNo      =6
  219. ERootFar        db 'Root directory not within first 64K DOS sectors'
  220. ERootFarL       =$-ERootFar
  221. EInvalidFuncNo  =7
  222. EInvalidFunc    db 'Program function not available'     ;stub message
  223. EInvalidFuncL   =$-EInvalidFunc
  224. ENoFATmemoryNo  =8
  225. ENoFATmemory    db 'Not enough memory for FAT'
  226. ENoFATmemoryL   =$-ENoFATmemory
  227. EFATnoMatchNo   =9
  228. EFATnoMatch     db 'File Allocation Tables do not match'
  229. EFATnoMatchL    =$-EFATnoMatch
  230. EInvalidDTANo    =10
  231. EInvalidDTA     db 'Unknown DOS DTA structure';CDS not 100% compat in DRDOS-5
  232. EInvalidDTAL    =$-EInvalidDTA                ;so use DTA structure after FindF
  233. EOS2No          =11                           ;to locate starting cluster of SD
  234. EOS2            db 'Cannot operate in OS/2 DOS box'
  235. EOS2L           =$-EOS2
  236. EMathNo         =12
  237. EMath           db 'Math overflow'
  238. EMathL          =$-EMath
  239. EFATlinkNo      =13
  240. EFATlink        db 'Too many file entries or FAT link corrupt'  ;less harsh
  241. EFATlinkL       =$-EFATlink
  242.  
  243.                 EVEN
  244. ErrMsgW         dw EDone,EDOS,EUnkSwitch,EInvalidDrv,EAccess,EUnkDevice
  245.                 dw ERootFar,EInvalidFunc,ENoFATmemory,EFATnoMatch,EInvalidDTA
  246.                 dw EOS2,EMath,EFATLink
  247.  
  248. ErrMsgL         db EDoneL,EDOSL,EUnkSwitchL,EInvalidDrvL,EAccessL,EUnkDeviceL
  249.                 db ERootFarL,EInvalidFuncL,ENoFATmemoryL,EFATnoMatchL,EInvalidDTAL
  250.                 db EOS2L,EMathL,EFATLinkL
  251.  
  252. ValidDevices    db 0,1,2,5,7,8  ;320/360,1.2,720,HD,1.44,2.88
  253. ValidDevicesL   =$-ValidDevices ;device types handled
  254.  
  255. SortOptions     db 'EN'         ;B3* options
  256. SortOptionsL    =$-SortOptions
  257. SortOrder       db 'E'
  258.  
  259. ThisDir         db '.',0        ;THIS subdirectory filename
  260.  
  261. Trap00          db 0            ;=1 then INT00 has been revectored
  262. Trap1B          db 0            ;=1 then INT1B has been revectored
  263. Trap23          db 0            ;=1 then INT23 has been revectored
  264. Trap24          db 0            ;=1 then INT24 has been revectored
  265.  
  266.                 .CODE
  267.  
  268. Bail:           sub     bh,bh
  269.                 push    bx              ;bail to DOS w/message and exitcode
  270.                 sub     ch,ch
  271.                 mov     cl,[bx+ErrMsgL]
  272.                 shl     bl,1
  273.                 mov     dx,[bx+ErrMsgW]
  274.                 mov     bx,STDOUT
  275.                 mov     ah,40h
  276.                 int 21h
  277.                 sub     bl,bl
  278.                 cmp     bl,Trap1B       ;changed INT1B vector?
  279.                 je      @F              ;no
  280.                 call    INT1Bswitch     ;yes,restore (INT23/24 restored by DOS)
  281. @@:             sub     bl,bl
  282.                 cmp     bl,Trap00       ;changed INT00 vector?
  283.                 je      @F              ;no
  284.                 call    INT00switch     ;yes,restore
  285. @@:             pop     ax
  286.                 mov     ah,4Ch
  287.                 int 21h
  288.  
  289.                 ;-----------------------
  290. BailDOS1:       mov     dx,OFFSET EDOS  ;bail back to DOS 1
  291.                 mov     ah,9
  292.                 int 21h
  293.                 retf
  294.  
  295.                 ;=======================
  296. Start:          push    ds              ;B1* DOS 1 exit return PSP:0
  297.                 sub     ax,ax
  298.                 push    ax
  299.  
  300.                 mov     ax,DGROUP
  301.                 mov     ds,ax
  302.                 mov     bx,es
  303.                 mov     PSPseg,bx
  304.                 mov     es,ax
  305.                 cli
  306.                 mov     ss,ax
  307.                 mov     sp,OFFSET STACK
  308.                 sti                     ;ds=es=ss=DGROUP
  309.                 ASSUME ds:DGROUP,es:DGROUP,ss:DGROUP
  310.  
  311.  
  312.                 ;-----------------------CHECK DOS VERSION
  313.                 mov     ah,30h
  314.                 int 21h
  315.                 cmp     al,2
  316.                 jb      BailDOS1        ;DOS 1 bail
  317.  
  318.                 mov     MajorV,al
  319.                 mov     MinorV,ah
  320.                 cmp     al,HIGH MinDOS
  321.                 mov     bl,EDOSNo       ;error message number
  322.                 ja      @F              ;major above min
  323.                 jb      Bail            ;major below min
  324.                 cmp     ah,LOW MinDOS
  325.                 jb      Bail            ;minor below min
  326.  
  327. @@:             ;-----------------------SHOW PROGRAM ID
  328. ID01:           mov     dx,OFFSET IDmsg
  329.                 mov     cx,IDmsgL
  330.                 mov     bx,STDOUT
  331.                 mov     ah,40h
  332.                 int 21h
  333.                 cmp     MajorV,10h      ;OS/2 DOS box?
  334.                 jb      @F              ;no
  335.                 mov     bl,EOS2No
  336.                 jmp     Bail
  337.  
  338. @@:             ;-----------------------DRIVE RESET
  339. DR01:           mov     ah,0Dh
  340.                 int 21h
  341.  
  342. @@:             ;-----------------------CHECK COMMAND LINE PARMS
  343. CL01:           mov     si,80h
  344.                 mov     ds,PSPseg       ;ds=PSP
  345.                 cld
  346.                 lodsb
  347.                 or      al,al           ;anything?
  348.                 jz      CL04            ;no
  349.  
  350. CL02:           lodsb
  351.                 cmp     al,13           ;CR then done
  352.                 je      CL04
  353.                 cmp     al,32           ;skip anything space or below
  354.                 jbe     CL02
  355.                 cmp     al,'/'          ;option must lead with slash
  356.                 jne     CL03
  357.                 lodsb                   ;we expect only 1 character
  358.                 and     al,255-32       ;upper case it
  359.  
  360.                 mov     cx,es           ;load ds=DGROUP
  361.                 mov     ds,cx
  362.  
  363.                 mov     di,OFFSET SortOptions
  364.                 mov     cx,SortOptionsL
  365.                 repne   scasb           ;repeat until found or not
  366.                 mov     SortOrder,al    ;use upper case
  367.                 je      @F              ;found
  368.  
  369. CL03:           mov     cx,es           ;load ds=DGROUP on bad switch leader
  370.                 mov     ds,cx
  371.                 mov     bl,EUnkSwitchNo
  372.                 jmp     Bail
  373.  
  374. CL04:           mov     ax,es           ;load ds=DGROUP on no parms
  375.                 mov     ds,ax
  376.  
  377. ;@@:             ;-----------------------VECTOR INT24 TO LOCAL HANDLER
  378. ;                ;Not used, let COMMAND query what to do since INT24 will occur
  379. ;                ;only using the non-IOCTL (which are used only to read drive)
  380. ;                ;INT1B/00 vectors not changed until after the non-IOCTL reads
  381. ;INT24trap:      mov     bl,1
  382. ;                call    INT24switch     ;DOS restores on exit
  383.  
  384. @@:             ;-----------------------VECTOR INT23 TO LOCAL HANDLER
  385. INT23trap:      mov     bl,1
  386.                 call    INT23switch     ;DOS restores on exit
  387.  
  388. @@:             ;-----------------------GET DEFAULT DRIVE
  389. GetDrv:         mov     ah,19h
  390.                 int 21h
  391.                 inc     ax              ;0=A,1=B,2=C,...
  392.                 mov     CurrDrive,al    ;1=A,2=B,3=C,...
  393.  
  394. @@:             ;-----------------------IS DRIVE REMOTE
  395. ChkRemote:      mov     bl,CurrDrive
  396.                 mov     ax,4409h
  397.                 int 21h
  398.                 test    dx,1000h        ;bit 12 drive is remote
  399.                 jz      @F              ;local drive
  400.                 mov     bl,EInvalidDrvNo
  401.                 jmp     Bail
  402.  
  403. @@:             ;-----------------------GET CURRENT DIRECTORY
  404. GetDir:         mov     dl,CurrDrive
  405.                 mov     si,OFFSET CurrDir
  406.                 mov     ah,47h
  407.                 int 21h
  408.  
  409. @@:             ;-----------------------GET STARTING CLUSTER OF SUBDIR
  410. GetStartClust:  mov     al,CurrDir
  411.                 or      al,al           ;root?
  412.                 jz      @F              ;yes,nevermind
  413.  
  414.                 mov     cx,10h          ;look for "."
  415.                 mov     dx,OFFSET ThisDir
  416.                 mov     ah,4Eh          ;find first file
  417.                 int 21h
  418.  
  419.                 push    es
  420.                 mov     es,PSPseg
  421.                 mov     ax,es:[81h]     ;get first two characters of template
  422.                 cmp     ax,' .'         ;should be dot-space, inteled
  423.                 mov     ax,es:[8Fh]     ;cluster number
  424.                 pop     es
  425.                 jne     GetStartClust01 ;was not dot-space
  426.                 mov     StartCluster,ax
  427.                 jmp     SHORT @F
  428.  
  429. GetStartClust01:mov     bl,EInvalidDTANo
  430.                 jmp     Bail
  431.  
  432. @@:             ;-----------------------VECTOR INT1B TO LOCAL HANDLER
  433. INT1Btrap:      mov     bl,1
  434.                 call    INT1Bswitch     ;this must be restored before exiting
  435.  
  436. @@:             ;-----------------------VECTOR INT00 TO LOCAL HANDLER
  437. INT00trap:      mov     bl,1
  438.                 call    INT00switch     ;this must be restored before exiting
  439.  
  440. @@:             ;-----------------------GET DEVICE PARMS
  441. GetDeviceParms: mov     bl,CurrDrive
  442.                 sub     bh,bh
  443.                 mov     cx,0860h
  444.                 mov     BuffDeviceParms.dpSpecFunc,1 ;get curr medium info
  445.                 mov     dx,OFFSET BuffDeviceParms
  446.                 mov     ax,440Dh
  447.                 int 21h
  448.                 jnc     @F
  449.                 mov     bl,EAccessNo
  450.                 jmp     Bail
  451.  
  452. @@:             ;-----------------------IS DEVICE KNOWN
  453. ChkDevice:      mov     al,BuffDeviceParms.dpDevType
  454.                 mov     di,OFFSET ValidDevices
  455.                 mov     cx,ValidDevicesL
  456.                 repne   scasb
  457.                 je      @F              ;can handle device
  458.                 mov     bl,EUnkDeviceNo
  459.                 jmp     Bail
  460. @@:             cmp     WPTR BuffDeviceParms.dpHiddenSecs+2,0
  461.                 je      @F
  462.                 mov     bl,ERootFarNo   ;root dir not in first 64K DOS sectors
  463.                 jmp     Bail
  464.  
  465. @@:             ;-----------------------CALC FAT/ROOT/DATA SECTOR START
  466. GetBase:        mov     ax,BuffDeviceParms.dpResSectors
  467.                 add     ax,WPTR BuffDeviceParms.dpHiddenSecs
  468.                 jc      GetBase01
  469.                 mov     bx,ax
  470.                 mov     FATsector,ax
  471.                 mov     al,BuffDeviceParms.dpFATs
  472.                 sub     ah,ah
  473.                 mul     BuffDeviceParms.dpFATsecs
  474.                 jc      GetBase01
  475.                 add     ax,bx
  476.                 jc      GetBase01
  477.                 mov     ROOTsector,ax
  478.                 mov     ax,BuffDeviceParms.dpRootDirEnts
  479.                 mov     cx,32
  480.                 mul     cx
  481.                 div     BuffDeviceParms.dpBytesSector
  482.                 mov     dx,ROOTsector
  483.                 add     ax,dx
  484.                 mov     DATAsector,ax
  485.                 mov     ax,BuffDeviceParms.dpBytesSector
  486.                 mov     dl,BuffDeviceParms.dpSectorsClust
  487.                 sub     dh,dh
  488.                 mul     dx
  489.                 jc      GetBase01
  490.                 mov     BytesCluster,ax
  491.                 jmp     SHORT @F
  492.  
  493. GetBase01:      mov     bl,ERootFarNo   ;root dir not in first 64K DOS sectors
  494.                 jmp     Bail
  495.  
  496. @@:             ;-----------------------CLEAR DIR SORT BUFFER
  497. ClearSortBuff:  sub     ax,ax
  498.                 mov     cx,SIZE BuffDirSort/2
  499.                 mov     di,OFFSET BuffDirSort
  500.                 rep     stosw
  501.  
  502. @@:             ;-----------------------DETERMINE SORT TYPE
  503. SortWhatDir:    call    ShowDrvInfo
  504.                 call    ShowDirInfo
  505.                 call    OutputCRLF
  506.                 mov     al,CurrDir
  507.                 or      al,al           ;root?
  508.                 jz      @F              ;yes
  509.                 jmp     SHORT SortSubDir
  510.  
  511. @@:             ;-----------------------SORT ROOT DIRECTORY
  512. SortRootDir:    mov     ax,BuffDeviceParms.dpRootDirEnts
  513.                 mov     cx,32
  514.                 mul     cx
  515.                 div     BuffDeviceParms.dpBytesSector
  516.                 mov     cx,ax                           ;cx=root dir sectors
  517.                 mov     ax,ROOTsector
  518.                 sub     dx,dx                           ;dx:ax=first DOS sector
  519.                 mov     di,OFFSET BuffDirSort+32        ;es:di->buffer
  520.                 call    ReadDOSsectors
  521.                 call    CountUsedEnts   ;cx=entries to sort,dx=last HSD entry
  522.                 mov     bp,di           ;di=deleted entries (still sorted)
  523.  
  524.                 push    cx              ;save entries to sort
  525.                 push    dx              ;save entries skipped
  526.  
  527.                 push    cx              ;and entries to sort again
  528.                 mov     di,OFFSET SortInfo
  529.                 mov     ax,dx
  530.                 sub     dx,dx
  531.                 call    Hex2ASCII
  532.                 dec     di              ;backup over Z
  533.                 mov     al,'/'          ;es:di->next slot in output buffer
  534.                 stosb
  535.                 pop     ax              ;get entries to sort
  536.                 sub     ax,bp           ;deleted entries not counted in list
  537.                 sub     dx,dx
  538.                 call    Hex2ASCII
  539.  
  540.                 pop     dx              ;get 'em back
  541.                 pop     cx
  542.                 cmp     cx,1            ;0 or 1 entries?
  543.                 jbe     @F              ;yes
  544.                 inc     dx              ;dx=first entry to start sort at
  545.                 add     cx,dx           ;A1*last item position+1
  546.                 dec     cx              ;A1*last item position
  547.                 call    QuiksortFN
  548.  
  549.                 sub     ax,ax
  550.                 sub     dx,dx           ;use same parms as read
  551.                 call    WriteDOSsectors
  552.  
  553. @@:             call    ShowSortInfo
  554.                 call    OutputCRLF
  555.                 sub     bl,bl           ;done okay
  556.                 jmp     Bail
  557.  
  558. @@:             ;-----------------------SORT SUBDIRECTORY
  559. SortSubDir:
  560. @@:             ;-----------------------ALLOCATE, LOAD (& COMPARE) FAT(S) BUFFER
  561. AllocReadFAT:   mov     ax,BuffDeviceParms.dpFATsecs
  562.                 mul     BuffDeviceParms.dpBytesSector
  563.                 jc      AllocReadFAT01  ;FAT > 64K-1
  564.                 mov     bp,ax           ;save bytes needed for FAT buffer
  565.                 mov     cl,4
  566.                 shr     ax,cl           ;get paras needed for FAT
  567.                 mov     bx,ax
  568.                 mov     ah,48h
  569.                 int 21h
  570.                 jc      AllocReadFAT01  ;not enough memory
  571.                 mov     SegBuffFAT,ax   ;segment of FAT buffer
  572.  
  573.                 cmp     BuffDeviceParms.dpFATs,1
  574.                 je      @F              ;only 1 FAT
  575.  
  576.                 mov     ah,48h          ;get buffer for FAT2
  577.                 int 21h
  578.                 jc      AllocReadFAT01  ;not enough memory
  579.                 mov     SegBuffFAT2,ax  ;segment of FAT2 buffer
  580.  
  581.                 sub     di,di           ;load FAT2
  582.                 mov     es,ax           ;es:di->FAT2 buffer
  583.                 mov     ax,FATsector
  584.                 add     ax,BuffDeviceParms.dpFATsecs
  585.                 sub     dx,dx           ;dx:ax=first FAT2 sector
  586.                 mov     cx,BuffDeviceParms.dpFATsecs ;sectors to read
  587.                 call    ReadDOSsectors
  588.  
  589. @@:             sub     di,di           ;load FAT
  590.                 mov     es,SegBuffFAT   ;es:di->FAT buffer
  591.                 mov     ax,FATsector
  592.                 sub     dx,dx           ;dx:ax=first FAT sector
  593.                 mov     cx,BuffDeviceParms.dpFATsecs ;sectors to read
  594.                 call    ReadDOSsectors
  595.  
  596.                 cmp     BuffDeviceParms.dpFATs,1
  597.                 je      @F              ;can't compare if only 1 FAT
  598.  
  599.                 mov     dx,ds           ;save ds in dx for a sec
  600.                 sub     si,si
  601.                 sub     di,di
  602.                 mov     es,SegBuffFAT2
  603.                 mov     ds,SegBuffFAT
  604.                 mov     cx,bp
  605.                 shr     cx,1            ;compare words
  606.                 repe    cmpsw
  607.                 jne     AllocReadFAT02  ;FATs do not match
  608.  
  609.                 mov     ah,49h          ;deallocate FAT 2 buffer
  610.                 int 21h
  611.                 mov     ds,dx           ;restore seg regs
  612.                 mov     es,dx
  613.                 jmp     SHORT @F
  614.  
  615. AllocReadFAT01: mov     bl,ENoFATmemoryNo
  616.                 jmp     Bail
  617.  
  618. AllocReadFAT02: mov     ds,dx           ;restore seg regs
  619.                 mov     es,dx
  620.                 mov     bl,EFATnoMatchNo
  621.                 jmp     Bail
  622.  
  623. @@:             ;-----------------------GET ALL CLUSTERS ASSIGNED TO THIS SUBDIR
  624. FATtruckin:     mov     FATtype,16
  625.                 mov     ax,BuffDeviceParms.dpSectors
  626.                 or      ax,ax           ;huge part?
  627.                 jz      @F              ;yes
  628.                 sub     dx,dx
  629.                 sub     bh,bh
  630.                 mov     bl,BuffDeviceParms.dpSectorsClust
  631.                 div     bx              ;ax=clusters on drive
  632.                 cmp     ax,4087         ;4087+ uses 16-bit FAT
  633.                 jae     @F
  634.                 mov     FATtype,12      ;else a 12-bit FAT
  635.  
  636. @@:             mov     cx,32           ;B2*determine how many clusters the
  637.                 mov     ax,MAXDIR       ;directory entry buffer is
  638.                 mul     cx              ;ax=MAXDIR*32=bytes available
  639.                 div     BytesCluster    ;ax=clusters available
  640.                 mov     cx,ax           ;count actual clusters available
  641.                 jcxz    @F              ;B2* buff not large enough for 1 cluster
  642.  
  643.                 push    ds
  644.                 mov     ds,SegBuffFAT   ;ds:si->FAT (si set in FollowFAT1x)
  645.                 mov     di,OFFSET ClusterList
  646.                 mov     ax,es:StartCluster      ;es:di->ClusterList array
  647. FATtruckin01:   stosw                           ;put links--
  648.                 cmp     es:FATtype,12           ;doing a 12-bit FAT?
  649.                 jne     FATtruckin02            ;no
  650.                 call    FollowFAT12             ;yes
  651.                 jmp     SHORT FATtruckin03
  652. FATtruckin02:   call    FollowFAT16             ;16-bit FAT
  653. FATtruckin03:   or      ax,ax                   ;0 then at end of link
  654.                 jz      FATtruckin04
  655.                 loop    FATtruckin01
  656.                 pop     ds                      ;ds=DGROUP
  657. @@:             mov     bl,EFATlinkNo           ;too many clusters for buffer
  658.                 jmp     Bail
  659. FATtruckin04:   stosw                           ;0 demarks end of ClusterList
  660.                 pop     ds                      ;ds=DGROUP
  661.  
  662. @@:             ;-----------------------READ SUBDIR CLUSTERS
  663. ReadSubDirClust:mov     si,OFFSET ClusterList   ;ds:si->ClusterList array
  664.                 mov     bl,BuffDeviceParms.dpSectorsClust
  665.                 sub     bh,bh           ;bx=sectors/cluster (sectors to read)
  666.                 mov     cx,bx           ;cx=sectors to read
  667.                 mov     di,OFFSET BuffDirSort+32 ;es:di=>dir sort buffer
  668.  
  669. @@:             lodsw                   ;get a cluster from list
  670.                 or      ax,ax           ;done?
  671.                 jz      SortSD01        ;yes
  672.                 dec     ax              ;no,convert cluster to DOS LOGSEC
  673.                 dec     ax              ;subtract 2...
  674.                 mul     bx              ;times sectors/cluster=DOS data sector
  675.                 add     ax,DATAsector   ;add in relative data start sector
  676.                 adc     dx,0            ;dx:ax=32-bit sector number
  677.                 push    bx              ;save multiplier
  678.                 push    cx              ;save sector read count
  679.                 push    di              ;save buffer address
  680.                 call    ReadDOSsectors  ;read cluster's sectors to buffer
  681.                 pop     di
  682.                 pop     cx
  683.                 pop     bx
  684.                 add     di,BytesCluster
  685.                 jmp     @B
  686.  
  687. @@:             ;-----------------------SORT SUBDIR BUFFER
  688. SortSD01:       mov     di,OFFSET BuffDirSort+32        ;es:di->buffer
  689.                 call    CountUsedEnts   ;cx=entries to sort,dx=last HSD entry
  690.                 mov     bp,di           ;di=deleted entries (still sorted)
  691.  
  692.                 push    cx              ;save entries to sort
  693.                 push    dx              ;save entries skipped
  694.  
  695.                 push    cx              ;and entries to sort again
  696.                 mov     di,OFFSET SortInfo
  697.                 mov     ax,dx
  698.                 sub     dx,dx
  699.                 call    Hex2ASCII
  700.                 dec     di              ;backup over Z
  701.                 mov     al,'/'          ;es:di->next slot in output buffer
  702.                 stosb
  703.                 pop     ax              ;get entries to sort
  704.                 sub     ax,bp           ;deleted entries not counted in list
  705.                 sub     dx,dx
  706.                 call    Hex2ASCII
  707.  
  708.                 pop     dx              ;get 'em back
  709.                 pop     cx
  710.                 cmp     cx,1            ;0 or 1 entries?
  711.                 jbe     SkipSort        ;yes
  712.                 inc     dx              ;dx=first entry to start sort at
  713.                 add     cx,dx           ;A1*last item position+1
  714.                 dec     cx              ;A1*last item position
  715.                 call    QuiksortFN
  716.  
  717. @@:             ;-----------------------WRITE SUBDIR CLUSTERS
  718. WriteSubDirClust:mov     si,OFFSET ClusterList   ;ds:si->ClusterList array
  719.                 mov     bl,BuffDeviceParms.dpSectorsClust
  720.                 sub     bh,bh           ;bx=sectors/cluster (sectors to read)
  721.                 mov     cx,bx           ;cx=sectors to read
  722.                 mov     di,OFFSET BuffDirSort+32 ;es:di=>dir sort buffer
  723.  
  724. @@:             lodsw                   ;get a cluster from list
  725.                 or      ax,ax           ;done?
  726.                 jz      @F              ;yes
  727.                 dec     ax              ;no,convert cluster to DOS LOGSEC
  728.                 dec     ax              ;subtract 2...
  729.                 mul     bx              ;times sectors/cluster=DOS data sector
  730.                 add     ax,DATAsector   ;add in relative data start sector
  731.                 adc     dx,0            ;dx:ax=32-bit sector number
  732.                 push    bx              ;save multiplier
  733.                 push    cx              ;save sector read count
  734.                 push    di              ;save buffer address
  735.                 call    WriteDOSsectors ;write cluster's sectors to buffer
  736.                 pop     di
  737.                 pop     cx
  738.                 pop     bx
  739.                 add     di,BytesCluster
  740.                 jmp     @B
  741. @@:
  742. SkipSort:       call    ShowSortInfo
  743.                 call    OutputCRLF
  744.  
  745. @@:             ;-----------------------DONE
  746. AllDone:        mov     ah,0Dh          ;drive reset
  747.                 int 21h
  748.  
  749.                 sub     bl,bl
  750.                 jmp     Bail
  751.  
  752.                 ;=======================
  753.                 ;SUBROUTINES
  754.  
  755.                 ;-----------------------FOLLOW FAT12 CHAIN
  756.                 ;USES: ax,bx,dx,si  RET: ax=next cluster,=0 if last link
  757. FollowFAT12:    test    ax,1            ;FAT entry number odd?
  758.                 pushf                   ;save for a sec
  759.                 mov     bx,3            ;determine if last link
  760.                 mul     bx              ;dx:ax=Link * 3
  761.                 shr     dx,1
  762.                 rcr     ax,1            ;dx:ax=Link * 1.5
  763.                 mov     si,ax
  764.                 mov     ax,[si]         ;get next cluster
  765.                 popf
  766.                 jnz     @F              ;yes odd
  767.                 and     ax,0FFFh        ;even link use right 12 bits
  768.                 jmp     SHORT FollowFAT1201
  769. @@:             shr     ax,1            ;odd link use left 12 bits
  770.                 shr     ax,1
  771.                 shr     ax,1
  772.                 shr     ax,1
  773. FollowFAT1201:  cmp     ax,0FF8h        ;end link?
  774.                 jb      @F              ;no
  775.                 sub     ax,ax           ;yes,return 0
  776. @@:             retn                    ;return cluster number
  777.  
  778.                 ;-----------------------FOLLOW FAT16 CHAIN
  779.                 ;USES: ax,si  RET: ax=next cluster,=0 if last in link
  780. FollowFAT16:    shl     ax,1            ;ax=ax*2
  781.                 mov     si,ax
  782.                 mov     ax,[si]         ;get link word
  783.                 cmp     ax,0FFF8h       ;end link?
  784.                 jb      @F              ;no
  785.                 sub     ax,ax           ;yes,return 0
  786. @@:             retn                    ;return cluster number
  787.  
  788.                 ;-----------------------CONV DOS LOGICAL SECTOR TO CYL/HD/SEC
  789.                 ;USES: ax,cx,dx  RET: DOScylinder,DOShead,DOSsector
  790. ConvLOGSEC:     mov     ax,BuffDeviceParms.dpSectorsTrack
  791.                 mul     BuffDeviceParms.dpHeads
  792.                 mov     cx,ax           ;cx=CylSec,sectors on cylinder
  793.                 mov     ax,WPTR LogSec
  794.                 mov     dx,WPTR LogSec+2 ;dx:ax=32-bit DOS sector
  795.                 div     cx              ;ax=cyl,cylinder of DOS sector
  796.                 mov     DOScylinder,ax
  797.                 mul     cx              ;dx:ax=cyl*CylSec
  798.                 sub     ax,WPTR LogSec
  799.                 sbb     dx,WPTR LogSec+2
  800.                 not     dx              ;negate
  801.                 neg     ax
  802.                 sbb     dx,-1           ;dx:ax=32-bit sector offset (dx=0)
  803.                 mov     cx,ax           ;cx=rm,sectors into this DOS cylinder
  804.                 div     BuffDeviceParms.dpSectorsTrack
  805.                 mov     DOShead,ax
  806.                 mul     BuffDeviceParms.dpSectorsTrack
  807.                 sub     cx,ax
  808.                 mov     DOSsector,cx
  809.                 retn
  810.  
  811.                 ;-----------------------ZERO BuffDirSort
  812.                 ;USES: ax,cx,di
  813. ZeroBuffDirSort:sub     ax,ax
  814.                 mov     cx,(MAXDIR+1)*32/2
  815.                 mov     di,OFFSET BuffDirSort
  816.                 rep     stosw
  817.                 retn
  818.  
  819.                 ;-----------------------COUNT DIRECTORY ENTRIES TO SORT
  820.                 ;USES: ax,bx,si,di RET: cx,dx,di  FIND LAST H/S/D ENTRY & DEL#
  821. CountUsedEnts:  mov     si,OFFSET BuffDirSort+32
  822.                 sub     cx,cx           ;track entries to sort
  823.                 mov     dx,cx           ;track last HSD entry
  824.                 mov     di,cx           ;track deleted entries
  825.                 mov     bx,31
  826. @@:             lodsb                   ;first byte of filename (0=unused entry)
  827.                 or      al,al           ;B4* unused?
  828.                 jz      CountUsedEnts3  ;B4*
  829.                 inc     cx              ;B4* used entry count
  830.                 mov     ah,[si+10]      ;attribute (si incremented by lodsb)
  831.                 test    ah,16h          ;system,hidden,subdir entry?
  832.                 jz      CountUsedEnts1  ;no
  833.                 cmp     al,0E5h         ;erased system,hidden,subdir entry?
  834.                 je      CountUsedEnts1  ;yes
  835.                 mov     dx,cx           ;current max hidden/system entry
  836.                 sub     di,di           ;zero deleted entries not skipped
  837. CountUsedEnts1: cmp     al,0E5h         ;track number of deleted entries
  838.                 jne     CountUsedEnts2
  839.                 inc     di
  840. CountUsedEnts2: add     si,bx
  841.                 jmp     @B
  842. CountUsedEnts3: sub     cx,dx           ;cx=directory entries to sort
  843.                 retn                    ;dx=last hidden/system/subdir entry or 0
  844.                                         ;di=deleted entries not skipped
  845.  
  846.                 ;-----------------------OUTPUT CR/LF
  847.                 ;USES: ah,bx,cx,dx
  848. OutputCRLF:     mov     dx,OFFSET CRLF
  849.                 mov     cx,2
  850.                 mov     bx,STDOUT
  851.                 mov     ah,40h
  852.                 int 21h
  853.                 retn
  854.  
  855.                 ;-----------------------SHOW DRIVE BEING SORTED
  856.                 ;USES: ax,bx,cx,dx
  857. ShowDrvInfo:    mov     al,CurrDrive
  858.                 add     al,'@'
  859.                 mov     CurrDrvMsg,al
  860.                 mov     dx,OFFSET CurrDrvMsgPre
  861.                 mov     cx,CurrDrvMsgPreL
  862.                 mov     bx,STDOUT
  863.                 mov     ah,40h
  864.                 int 21h
  865.                 retn
  866.  
  867.                 ;-----------------------SHOW DIRECTORY BEING SORTED
  868.                 ;USES: ax,bx,cx,dx,di
  869. ShowDirInfo:    mov     cx,40h          ;max dir length
  870.                 mov     di,OFFSET CurrDir
  871.                 sub     al,al
  872.                 repne   scasb
  873.                 sub     cx,40h
  874.                 neg     cx
  875.                 dec     cx
  876.                 jcxz    @F
  877.                 mov     dx,OFFSET CurrDir
  878.                 mov     bx,STDOUT
  879.                 mov     ah,40h
  880.                 int 21h
  881. @@:             retn
  882.  
  883.                 ;-----------------------SHOW SORT INFO
  884.                 ;USES: ah,bx,cx,dx
  885. ShowSortInfo:   mov     dx,OFFSET MSortInfo
  886.                 mov     cx,MSortInfoL
  887.                 mov     bx,STDOUT
  888.                 mov     ah,40h
  889.                 int 21h
  890. @@:             retn
  891.  
  892.                 ;-----------------------READ TRACK ON LOGICAL DRIVE
  893.                 ;USES: ax,bx,cx,dx  RET: NC=okay CY=error in ax
  894. ReadTrack:      mov     bl,CurrDrive
  895.                 sub     bh,bh
  896.                 mov     cx,0861h        ;device category/read track
  897.                 mov     dx,OFFSET rBlock ;read block structure
  898.                 mov     ax,440Dh
  899.                 int 21h
  900.                 retn                    ;carry set on error/ax=1,2,5
  901.  
  902.                 ;-----------------------WRITE TRACK ON LOGICAL DRIVE
  903.                 ;USES: ax,bx,cx,dx  RET: NC=okay CY=error in ax
  904. WriteTrack:     mov     bl,CurrDrive
  905.                 sub     bh,bh
  906.                 mov     cx,0841h        ;device category/write track
  907.                 mov     dx,OFFSET wBlock ;write block structure
  908.                 mov     ax,440Dh
  909.                 int 21h
  910.                 retn                    ;carry set on error/ax=1,2,5
  911.  
  912.                 ;-----------------------READ CX DOS SECTORS AT DX:AX TO ES:DI
  913.                 ;USES: ax,cx,dx          (CONSECUTIVE PHYSICAL SECTORS)
  914. ReadDOSsectors: mov     WPTR LOGSEC,ax
  915.                 mov     WPTR LOGSEC+2,dx
  916.                 sub     ax,ax
  917.                 mov     rBlock.rwSpecFunc,al
  918.                 mov     wBlock.rwSpecFunc,al    ;load write block too
  919.                 push    cx
  920.                 call    ConvLOGSEC
  921.                 pop     cx
  922.                 mov     ax,DOShead
  923.                 mov     rBlock.rwHead,ax
  924.                 mov     wBlock.rwHead,ax
  925.                 mov     ax,DOScylinder
  926.                 mov     rBlock.rwCylinder,ax
  927.                 mov     wBlock.rwCylinder,ax
  928.                 mov     ax,DOSsector
  929.                 mov     rBlock.rwFirstSector,ax
  930.                 mov     wBlock.rwFirstSector,ax
  931.                 mov     rBlock.rwSectors,cx
  932.                 mov     wBlock.rwSectors,cx
  933.                 mov     WPTR rBlock.rwBuffer,di
  934.                 mov     WPTR rBlock.rwBuffer+2,es
  935.                 mov     WPTR wBlock.rwBuffer,di
  936.                 mov     WPTR wBlock.rwBuffer+2,es
  937.                 call    ReadTrack
  938.                 jnc     @F
  939.                 mov     bl,EAccessNo
  940.                 jmp     Bail
  941. @@:             retn
  942.  
  943.                 ;-----------------------WRITE CX DOS SECTORS AT DX:AX FROM ES:DI
  944.                 ;USES: ax,cx,dx          (CONSECUTIVE PHYSICAL SECTORS)
  945. WriteDOSsectors:or      ax,ax           ;use same info as last read?
  946.                 jnz     @F              ;no
  947.                 or      dx,dx
  948.                 jz      WriteSame       ;yes, use last read's parms
  949. @@:             mov     WPTR LOGSEC,ax
  950.                 mov     WPTR LOGSEC+2,dx
  951.                 sub     ax,ax
  952.                 mov     wBlock.rwSpecFunc,al
  953.                 push    cx
  954.                 call    ConvLOGSEC
  955.                 pop     cx
  956.                 mov     ax,DOShead
  957.                 mov     wBlock.rwHead,ax
  958.                 mov     ax,DOScylinder
  959.                 mov     wBlock.rwCylinder,ax
  960.                 mov     ax,DOSsector
  961.                 mov     wBlock.rwFirstSector,ax
  962.                 mov     wBlock.rwSectors,cx
  963.                 mov     WPTR wBlock.rwBuffer,di
  964.                 mov     WPTR wBlock.rwBuffer+2,es
  965. WriteSame:      call    WriteTrack
  966.                 jnc     @F
  967.                 mov     bl,EAccessNo
  968.                 jmp     Bail
  969. @@:             retn
  970.  
  971.                 ;-----------------------OUTPUT DX:AX IN ASCII TO ES:DI
  972.                 ;USES: ax,bx,cx,dx,si,di RET: di->next slot,ASCII output @ ES:DI
  973. Hex2ASCII:      mov     si,10           ;base
  974.                 mov     bx,ax
  975.                 mov     cx,dx
  976.                 mov     dx,-1           ;conv digits stored on stack after -1
  977.                 push    dx
  978. Hex2ASCII01:    xchg    ax,cx           ;ax=high word
  979.                 sub     dx,dx
  980.                 div     si
  981.                 xchg    cx,ax           ;cx=high divide
  982.                 xchg    ax,bx           ;ax=low word,dx=remainder
  983.                 div     si
  984.                 xchg    bx,ax           ;bx=low divide
  985.  
  986.                 add     dl,'0'          ;make ASCII
  987.                 push    dx              ;save 'em
  988.                 or      bx,bx           ;more left to divide?
  989.                 jne     Hex2ASCII01     ;yes
  990.                 or      cx,cx
  991.                 jne     Hex2ASCII01     ;yes
  992.  
  993.                 mov     bl,'0'          ;in case dx:ax=0 and leading zero flag
  994. Hex2ASCII02:    pop     dx              ;get 'em
  995.                 cmp     dx,-1           ;all done?
  996.                 je      Hex2ASCII04     ;yes
  997.                 or      bl,dl           ;set bl to indicate leading '0' or not
  998.                 cmp     bl,'0'          ;still a leading zero?
  999.                 je      @F              ;yes,skip it
  1000.                 mov     al,dl
  1001.                 stosb
  1002. @@:             jmp     SHORT Hex2ASCII02
  1003.  
  1004. Hex2ASCII04:    cmp     bl,'0'          ;dx:ax=0?
  1005.                 jne     @F              ;no
  1006.                 mov     al,bl
  1007.                 stosb
  1008. @@:             sub     al,al           ;zero terminate it
  1009.                 stosb
  1010.                 retn
  1011.  
  1012. COMMENT ~ Not needed, see above
  1013.                 ;-----------------------TRAP INT24
  1014.                 ;USES: none
  1015. INT24switch:    push    es
  1016.                 push    ds
  1017.                 push    dx
  1018.                 push    ax
  1019.  
  1020.                 mov     Trap24,bl
  1021.                 or      bl,bl           ;trap or restore?
  1022.                 jz      INT24s2         ;0=restore
  1023.  
  1024.                 mov     INT24error,0
  1025.                 mov     ax,3524h
  1026.                 int 21h
  1027.                 mov     INT24seg,es
  1028.                 mov     INT24off,bx
  1029.                 mov     ax,2524h
  1030.                 mov     dx,OFFSET INT24handler
  1031.                 push    cs
  1032.                 pop     ds
  1033. INT24s1:        int 21h
  1034.                 pop     ax
  1035.                 pop     dx
  1036.                 pop     ds
  1037.                 pop     es
  1038.                 retn
  1039.  
  1040. INT24s2:        mov     ax,2524h
  1041.                 mov     dx,INT24off
  1042.                 mov     ds,INT24seg
  1043.                 jmp     INT24s1
  1044.  
  1045. INT24handler:   sti                     ;INT24 HANDLER
  1046.                 add     sp,6
  1047.                 mov     ax,di
  1048.                 sub     ah,ah
  1049.                 add     ax,13h
  1050.                 mov     ss:INT24error,ax
  1051.                 pop     ax
  1052.                 pop     bx
  1053.                 pop     cx
  1054.                 pop     dx
  1055.                 pop     si
  1056.                 pop     di
  1057.                 pop     bp
  1058.                 pop     ds
  1059.                 pop     es
  1060.                 iret
  1061. END COMMENT ~
  1062.  
  1063.                 ;-----------------------TRAP INT23
  1064.                 ;USES: none
  1065. INT23switch:    push    es
  1066.                 push    ds
  1067.                 push    dx
  1068.                 push    ax
  1069.  
  1070.                 mov     Trap23,bl
  1071.                 or      bl,bl           ;trap or restore?
  1072.                 jz      INT23s2         ;0=restore
  1073.  
  1074.                 mov     ax,3523h
  1075.                 int 21h
  1076.                 mov     INT23seg,es
  1077.                 mov     INT23off,bx
  1078.                 mov     ax,2523h
  1079.                 mov     dx,OFFSET INT23handler
  1080.                 push    cs
  1081.                 pop     ds
  1082. INT23s1:        int 21h
  1083.                 pop     ax
  1084.                 pop     dx
  1085.                 pop     ds
  1086.                 pop     es
  1087.                 retn
  1088.  
  1089. INT23s2:        mov     ax,2523h
  1090.                 mov     dx,INT23off
  1091.                 mov     ds,INT23seg
  1092.                 jmp     INT23s1
  1093.  
  1094. INT23handler:   iret                    ;INT23 HANDLER
  1095.  
  1096.                 ;-----------------------TRAP INT1B
  1097.                 ;USES: none
  1098. INT1Bswitch:    push    es
  1099.                 push    ds
  1100.                 push    dx
  1101.                 push    ax
  1102.  
  1103.                 mov     Trap1B,bl
  1104.                 or      bl,bl           ;trap or restore?
  1105.                 jz      INT1Bs2         ;0=restore
  1106.  
  1107.                 mov     ax,351Bh
  1108.                 int 21h
  1109.                 mov     INT1Bseg,es
  1110.                 mov     INT1Boff,bx
  1111.                 mov     ax,251Bh
  1112.                 mov     dx,OFFSET INT1Bhandler
  1113.                 push    cs
  1114.                 pop     ds
  1115. INT1Bs1:        int 21h
  1116.                 pop     ax
  1117.                 pop     dx
  1118.                 pop     ds
  1119.                 pop     es
  1120.                 retn
  1121.  
  1122. INT1Bs2:        mov     ax,251Bh
  1123.                 mov     dx,INT1Boff
  1124.                 mov     ds,INT1Bseg
  1125.                 jmp     INT1Bs1
  1126.  
  1127. INT1Bhandler:   push    ax              ;INT1B HANDLER
  1128.                 mov     al,20h
  1129.                 out     20h,al
  1130.                 pop     ax
  1131.                 iret
  1132.  
  1133.                 ;-----------------------TRAP INT00
  1134.                 ;USES: none
  1135. INT00switch:    push    es
  1136.                 push    ds
  1137.                 push    dx
  1138.                 push    ax
  1139.  
  1140.                 mov     Trap00,bl
  1141.                 or      bl,bl           ;trap or restore?
  1142.                 jz      INT00s2         ;0=restore
  1143.  
  1144.                 mov     ax,3500h
  1145.                 int 21h
  1146.                 mov     INT00seg,es
  1147.                 mov     INT00off,bx
  1148.                 mov     ax,2500h
  1149.                 mov     dx,OFFSET INT00handler
  1150.                 push    cs
  1151.                 pop     ds
  1152. INT00s1:        int 21h
  1153.                 pop     ax
  1154.                 pop     dx
  1155.                 pop     ds
  1156.                 pop     es
  1157.                 retn
  1158.  
  1159. INT00s2:        mov     ax,2500h
  1160.                 mov     dx,INT00off
  1161.                 mov     ds,INT00seg
  1162.                 jmp     INT00s1
  1163.  
  1164. INT00handler:   add     sp,6                    ;remove iret junk
  1165.                 mov     bl,EMathNo              ;INT00 HANDLER
  1166.                 jmp     Bail
  1167.  
  1168.                 ;-----------------------SORT DIRSORT BUFFER BY FILENAME/EXT
  1169.                 ;Use your own sort routine
  1170.                 ;if SortMode='@' or 'N' sort by filename, if 'E' then extension
  1171.                 ;dir entries start at BuffDirSort+32
  1172.                 ;with cx=last entry to sort dx=entry to start sort at
  1173. QuiksortFN:     mov     bl,EInvalidFuncNo
  1174.                 jmp     Bail
  1175.  
  1176.                 END Start
  1177.  
  1178.  
  1179.  
  1180.